import pygame, sys,os
from invaderplayer import Player
import obstacle
from alien import Alien,Extra
from random import choice, randint
from alienlaser import AlienLaser
from food import Food

# set the delaying and character showing
stop = False
show1 = True
show2 = True
show3 = True
show4 = True

# basic function
# text drawing
def draw_text(text,font,text_col,x,y):
    img = font.render(text, True, text_col) 
    screen.blit(img,(x,y))



# draw the name-card of the character
# for the Bacteria
def show_charactercard(x,y):

    # set the delaying time
    waiting = True
    waited_time = pygame.time.get_ticks()

    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
        # character name
        draw_text('Bacteria',pygame.font.SysFont('Lucida Sans', 24),'white',x,y)
        pygame.display.update()
        clock.tick(15)
        
        # set the waiting time
        if pygame.time.get_ticks() - waited_time > 200:
            waiting = False

# for the Food
def show_charactercard2(x,y):
    waiting = True
    waited_time = pygame.time.get_ticks()
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
        draw_text('Food',pygame.font.SysFont('Lucida Sans', 24),'white',x,y)
        pygame.display.update()
        clock.tick(15)
        if pygame.time.get_ticks() - waited_time > 1000:
            waiting = False

# for the Attacter from bacteria
def show_charactercard3(x,y):
    waiting = True
    waited_time = pygame.time.get_ticks()
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
        draw_text('Attacter',pygame.font.SysFont('Lucida Sans', 24),'white',x,y)
        pygame.display.update()
        clock.tick(15)
        if pygame.time.get_ticks() - waited_time > 1000:
            waiting = False

# for the Enzyme
def show_charactercard4(x,y):
    waiting = True
    waited_time = pygame.time.get_ticks()
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
        draw_text('Enzyme',pygame.font.SysFont('Lucida Sans', 24),'white',x,y)
        pygame.display.update()
        clock.tick(15)
        if pygame.time.get_ticks() - waited_time > 1000:
            waiting = False

class Game:
    def __init__(self):
        # player setup
        player_sprite = Player((screen_width / 2,screen_height),screen_width,5)
        self.player = pygame.sprite.GroupSingle(player_sprite)

        # health and score setup
        self.lives = 3
        self.live_surf = pygame.image.load('../graphics/live.png').convert_alpha()
        self.live_x_start_pos = screen_width - (self.live_surf.get_size()[0] * 3 + 10)
        self.score = 0
        self.font = pygame.font.Font(None,40)

        # obstacle setup
        self.shape = obstacle.shape
        self.block_size = 6
        self.blocks = pygame.sprite.Group()
        self.obstacle_amount = 4
        self.obstacle_x_positions = [num * (screen_width/ self.obstacle_amount) for num in range(self.obstacle_amount)]
        self.create_multiple_obstacles(*self.obstacle_x_positions, x_start = screen_width / 15, y_start = 480) #unpacking the stray

        # alien setup
        self.aliens = pygame.sprite.Group()
        self.alien_lasers = pygame.sprite.Group()
        self.foods = pygame.sprite.Group()
        self.alien_setup(rows = 5, cols = 4)
        self.alien_direction = 1

        # extra setup
        self.extra = pygame.sprite.GroupSingle()
        self.extra_spawn_time = randint(1,2)

    # set the obstacle as seperate sprites
    # create one obstacle
    def create_obstacle(self, x_start, y_start, offset_x):
        # seperate all the blockes from x axis and y axis
        for row_index,row in enumerate(self.shape):
            for col_index,col in enumerate(row):
                if col == 'x':
                    x = x_start + col_index * self.block_size + offset_x # draw little squares, offset is the x-position for the obstacle
                    y = y_start + row_index * self.block_size
                    block = obstacle.Block(self.block_size,(241,79,80),x,y)
                    self.blocks.add(block)

    # create multiple obstacles
    def create_multiple_obstacles(self,*offset,x_start,y_start):  #*offset: already put into a tuple
        for offset_x in offset:
            self.create_obstacle(x_start, y_start,offset_x)

    # set up bacteria
    def alien_setup(self,rows,cols,x_distance = 60, y_distance = 48,x_offset = 70, y_offset = 100):
        # similar to the setting of obstacles
        # establish the bacteria lines and rows
        for row_index,row in enumerate(range(rows)):
            for col_index,col in enumerate(range(cols)): 
                x = col_index * x_distance + x_offset
                y = row_index * y_distance + y_offset
                
                # set up different bacteria types
                if row_index == 0:
                    alien_sprite = Alien('red',x,y)
                elif row_index == 2:
                    alien_sprite = Alien('green',x,y)
                else:
                    alien_sprite = Alien('blue',x,y)
                self.aliens.add(alien_sprite)

    # controling the left-and-right movements and down movements
    def alien_position_checker(self):
        all_aliens = self.aliens.sprites()
        for alien in all_aliens:
            if alien.rect.right >= screen_width:
                self.alien_direction = -1
                self.alien_move_down(2)
            elif alien.rect.left <= 0:
                self.alien_direction = 1
                self.alien_move_down(2)

    # check collision and move down 2 each collision
    def alien_move_down(self,distance):
        # all the sprites need to move down
        if self.aliens:
            for alien in self.aliens.sprites():
                alien.rect.y += distance

    # attacker generating
    def alien_shoot(self):
        if self.aliens.sprites():
            random_alien = choice(self.aliens.sprites()) #select single
            laser_sprite = AlienLaser(random_alien.rect.center,6,screen_height)
            self.alien_lasers.add(laser_sprite)

    # food generating
    def food(self):
        random_place = randint(0,int(screen_width))  #select single
        food_sprite = Food((random_place,0),4,screen_height)
        self.foods.add(food_sprite)

    # add the timer for the attacter
    # avoid countinuous attacting
    def extra_alien_timer(self):
        self.extra_spawn_time -= 1
        if self.extra_spawn_time <= 0:
            self.extra.add(Extra(choice(['right','left']),screen_width,screen_height)) # come from either right or left
            self.extra_spawn_time = randint(400,800) # re-initialize

    # check the collision
    def collision_checks(self):
        # player lasers
        if self.player.sprite.lasers:
            for laser in self.player.sprite.lasers:
                # obstacle collisions
                if pygame.sprite.spritecollide(laser,self.blocks,True):  # do kill = True
                    laser.kill() # destroy the laser
                
                # alien collision
                aliens_hit = pygame.sprite.spritecollide(laser, self.aliens, True)
                if aliens_hit:
                    laser.kill() #destroy the laser
        
        # alien lasers
        if self.alien_lasers:
            for laser in self.alien_lasers:
                if pygame.sprite.spritecollide(laser,self.blocks,True): # do kill = True
                    laser.kill() #destroy the laser

                if pygame.sprite.spritecollide(laser,self.player,False): 
                    laser.kill() 
                    self.lives -= 1

        # foods
        if self.foods:
            for food in self.foods:
                if pygame.sprite.spritecollide(food,self.blocks,False): 
                    food.kill() #destroy the food
                if pygame.sprite.spritecollide(food,self.player,False):  
                    food.kill() 
                    self.lives -= 1

        # aliens
        if self.aliens:
            for alien in self.aliens:
                pygame.sprite.spritecollide(alien,self.blocks,True)   
                if pygame.sprite.spritecollide(alien,self.player,False): # do kill = True
                    self.lives = -1
        
        # extra
        if self.extra:
            for extra in self.extra:
                if pygame.sprite.spritecollide(extra,self.player,False): # do kill = True
                    self.score += 5
                    extra.kill() # destroy the laser

    # show the lives
    def display_lives(self):
        for live in range(self.lives):
            x = self.live_x_start_pos + (live * (self.live_surf.get_size()[0] + 5)) # draw the live icons on the screen
            screen.blit(self.live_surf,(x,8))

    # show the score
    def display_score(self):
        score_surf = self.font.render(f'score: {self.score}',False, 'white') # input the score and put on screen
        score_rect = score_surf.get_rect(topleft = (0,0))
        screen.blit(score_surf,score_rect)

    # win
    def victory_message(self):
        if not self.aliens.sprites() and self.lives > 0 and self.score >= 30:
            if self.foods:
                for food in self.foods:
                    food.kill() # stop generating foods
            screen.fill('black')
            draw_text('YOU WIN!',font_big,'yellow',200,200)
            draw_text('PRESS SPACE TO EXIT',font_big,'white',150,300)
            draw_text('Press ENTER TO THE NEXT LEVEL',font_big,'white',100,350)
            key = pygame.key.get_pressed()
            if key[pygame.K_SPACE]:
                pygame.quit()
                sys.exit()
            elif key[pygame.K_RETURN]:
                pygame.quit()
                os.system('cd ../../level_4/mainpy & python main.py')
                quit()


    # lose (similar to above)
    def check_death(self):
        if self.lives <= 0:    
            if self.aliens:
                for alien in self.aliens:
                    alien.kill()
            if self.foods:
                for food in self.foods:
                    food.kill()
            screen.fill('black')
            draw_text('TRY AGAIN!',font_big,'white',200,200)
            # exit
            draw_text('PRESS SPACE TO EXIT',font_big,'white',150,300)
            # play again
            draw_text('PRESS ENTER TO PLAY Again',font_big,'white',100,350)
            key = pygame.key.get_pressed()
            if key[pygame.K_SPACE]:
                pygame.quit()
                sys.exit()
            elif key[pygame.K_RETURN]:
                pygame.quit()
                os.system('python main.py')
                quit()


    def run(self):
        #update all sprite groups
        self.player.update()
        self.alien_lasers.update()
        self.foods.update()
        self.extra.update()

        self.aliens.update(self.alien_direction)
        self.alien_position_checker()
        self.extra_alien_timer()
        self.collision_checks()

        #draw all sprite groups
        self.player.sprite.lasers.draw(screen)
        self.player.draw(screen)
        self.blocks.draw(screen)
        self.aliens.draw(screen)
        self.alien_lasers.draw(screen)
        self.foods.draw(screen)
        self.extra.draw(screen)
        self.display_lives()
        self.display_score()
        self.victory_message()
        self.check_death()

class Background():
    def __init__(self,alt = 0):
        #background
        self.back = pygame.image.load('../graphics/bg.png')
        self.back_rect = self.back.get_rect()
        self.back_rect.y = alt
    
    # set the scroll in y direction
    def update(self):
        self.back_rect.y += 1
        if self.back_rect.centery >= 1000:
            self.back_rect.y = -screen_height

    def draw(self):
        screen.blit(self.back,self.back_rect)
        
if __name__ == '__main__':
    # set the screen parameter
    pygame.init()
    font_big = pygame.font.SysFont('Lucida Sans', 25)
    screen_width = 600
    screen_height = 600
    screen = pygame.display.set_mode((screen_width,screen_height))
    clock = pygame.time.Clock()
    game = Game()
    back = Background()
    back1 = Background(-screen_height)

    #control when to call the alienlaser method
    ALIENLASER = pygame.USEREVENT + 2
    pygame.time.set_timer(ALIENLASER,1300) #1300 msec
    FOOD = pygame.USEREVENT + 1
    pygame.time.set_timer(FOOD,3000)

    while True:
        # show the name card
        # bacteria
        if show1:
            for enemy in game.aliens:
                if enemy.rect.x >= screen_width/2:
                    show_charactercard(enemy.rect.left, enemy.rect.top-30)
                    show1 = False 
        # food
        if show2:
            for food in game.foods:
                if food.rect.y >= screen_height/2:
                    show_charactercard2(food.rect.left, food.rect.top-30)
                    show2 = False
        # attacter
        if show3:
            for attacter in game.alien_lasers:
                if attacter.rect.y >= screen_height/2:
                    show_charactercard3(attacter.rect.left, attacter.rect.top-30)
                    show3 = False
        #enzyme
        if show4:
            for enzyme in game.extra:
                if enzyme.rect.y >= screen_height/2:
                    show_charactercard4(enzyme.rect.left, enzyme.rect.top-30)
                    show4 = False

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            # control when to call the alienlaser method
            if event.type == ALIENLASER:
                game.alien_shoot()#control when to call the alienlaser method
            if event.type == FOOD:
                game.food() 
        
        # set the stop key, p for pause, z for continue
        key = pygame.key.get_pressed()
        if key[pygame.K_p]:
            stop = True
        while stop:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
            key = pygame.key.get_pressed() # must be called twice here!
            if key[pygame.K_z]:
                stop = False
        
        screen.fill((30,30,30))
        
        # draw the background
        back.update()
        back.draw()
        back1.update()
        back1.draw()
        
        # run the game
        game.run()

        pygame.display.flip()
        clock.tick(60)
